import javax.swing.JToolBar;

import javax.swing.JButton;
import javax.swing.ImageIcon;
import javax.swing.JTextField;
import javax.swing.event.*;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.GroupLayout;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPasswordField;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JScrollPane;
import javax.swing.JPanel;
import javax.swing.RowFilter;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.SwingUtilities;

import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableRowSorter;
import com.toedter.calendar.JCalendar;

import java.math.BigDecimal;
import java.net.URL;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.Stack;
import java.util.Vector;

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.print.PrinterException;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

public class GUISwing extends JPanel implements ActionListener {
	static final private String UNDO = "undo";
	static final private String REDO = "redo";
	static final private String ADD = "add";
	static final private String EDIT = "edit";
	static final private String DELETE = "delete";
	static final private String SEARCH = "search";
	static final private String PRINT = "print";
	static final private String SAVE = "save";
	static final private String LOGOUT = "logout";
	static final private String TEXT_ENTERED = "text";

	static final private String categoryBoxItems[] = { "Food", "Transport",
			"Utility", "Beverage", "ETC" };
	static final private String paymentMethodBoxItems[] = { "Nets", "Cash",
			"Credit Card" };

	private boolean undo;
	private boolean redo;
	JButton undoButton;
	JButton redoButton;
	Stack<UndoRedoItem> undoStack = new<UndoRedoItem> Stack();
	Stack<UndoRedoItem> redoStack = new<UndoRedoItem> Stack();

	JComboBox<String> categoryBox = new JComboBox<String>(categoryBoxItems);
	JComboBox<String> paymentMethodBox = new JComboBox<String>(
			paymentMethodBoxItems);
	JTextField descriptionField = new JTextField();
	JTextField price = new JTextField();
	JTextField date = new JTextField();
	JTextField searchField = new JTextField();

	JTabbedPane tableTabs;

	ExpenseTableModel expenseModel;
	JTable expenseTable;
	IncomeTableModel incomeModel;
	JTable incomeTable;
	BillTableModel billModel;
	JTable billTable;

	TableRowSorter<ExpenseTableModel> expenseSorter;
	TableRowSorter<IncomeTableModel> incomeSorter;
	TableRowSorter<BillTableModel> billSorter;

	Profile myProfile;
	JList<String> alertsList;
	JLabel budgetLabel;
	ActionEvent searchAction = new ActionEvent(new Button(), 0, "SEARCH");

	public GUISwing() {
		super(new BorderLayout());

		// Create the toolbar.
		JToolBar toolBar = new JToolBar();
		addButtons(toolBar);
		toolBar.setFloatable(false);
		toolBar.setRollover(true);

		JPanel leftPanel = new JPanel();
		leftPanel.setLayout(new BorderLayout(0, 0));
		// leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.Y_AXIS));
		leftPanel.setBorder(BorderFactory.createLineBorder(new Color(102, 102,
				153)));
		leftPanel.setPreferredSize(new Dimension(150, 100)); // set size of left
																// panel

		// Add in alerts label and then align them at the centre
		JLabel alertsLabel = new JLabel("Alerts", SwingConstants.CENTER);
		alertsLabel.setFont(new Font("Dialog", Font.PLAIN, 24));
		alertsLabel.setAlignmentX(CENTER_ALIGNMENT);
		alertsLabel.setBorder(BorderFactory.createMatteBorder(4, 4, 4, 4,
				new Color(204, 204, 255)));
		leftPanel.add(alertsLabel, BorderLayout.NORTH);

		// Alerts
		alertsList = new JList<String>();

		alertsList.setAlignmentX(CENTER_ALIGNMENT);
		alertsList.setBackground(null);
		alertsList.setBorder(BorderFactory.createMatteBorder(4, 4, 4, 4,
				new Color(204, 204, 255)));
		leftPanel.add(alertsList, BorderLayout.CENTER);

		// Add in Budget
		budgetLabel = new JLabel("BUDGET", SwingConstants.CENTER);
		budgetLabel.setFont(new Font("Dialog", Font.PLAIN, 40));
		budgetLabel.setBackground(new Color(204, 204, 255));
		budgetLabel.setBorder(BorderFactory.createMatteBorder(4, 4, 4, 4,
				new Color(0, 0, 0)));
		budgetLabel.setOpaque(true);
		leftPanel.add(budgetLabel, BorderLayout.SOUTH);

		// Add in expense list
		expenseModel = new ExpenseTableModel();
		expenseTable = new JTable(expenseModel);
		expenseSorter = new TableRowSorter<ExpenseTableModel>(expenseModel);
		incomeModel = new IncomeTableModel();
		incomeTable = new JTable(incomeModel);
		incomeSorter = new TableRowSorter<IncomeTableModel>(incomeModel);
		billModel = new BillTableModel();
		billTable = new JTable(billModel);
		billSorter = new TableRowSorter<BillTableModel>(billModel);
		addPayBillButtons();

		TableColumnModel m = expenseTable.getColumnModel();
		m.getColumn(2).setCellRenderer(new RenderPrice());
		m = incomeTable.getColumnModel();
		m.getColumn(1).setCellRenderer(new RenderPrice());

		expenseTable.setPreferredScrollableViewportSize(new Dimension(500, 70));
		expenseTable.setFillsViewportHeight(true);
		expenseTable.setAutoCreateRowSorter(true);

		incomeTable.setPreferredScrollableViewportSize(new Dimension(500, 70));
		incomeTable.setFillsViewportHeight(true);
		incomeTable.setAutoCreateRowSorter(true);

		billTable.setPreferredScrollableViewportSize(new Dimension(500, 70));
		billTable.setFillsViewportHeight(true);
		billTable.setAutoCreateRowSorter(true);

		// Create the scroll pane and add the table to it.

		JScrollPane expenseScrollPane = new JScrollPane();
		expenseScrollPane.setViewportView(expenseTable);
		JScrollPane incomeScrollPane = new JScrollPane();
		incomeScrollPane.setViewportView(incomeTable);
		JScrollPane billScrollPane = new JScrollPane();
		billScrollPane.setViewportView(billTable);

		// Tabbed Pane
		tableTabs = new JTabbedPane();
		tableTabs.add(expenseScrollPane, "Expenses");
		tableTabs.add(incomeScrollPane, "Income");
		tableTabs.add(billScrollPane, "Bills");

		// Lay out the main panel.
		setPreferredSize(new Dimension(1350, 650));
		setLayout(new GridBagLayout());
		GridBagConstraints toolBarC = new GridBagConstraints();
		toolBarC.fill = GridBagConstraints.BOTH;
		toolBarC.weightx = 1;
		toolBarC.gridx = 0;
		toolBarC.gridy = 0;
		toolBarC.gridwidth = 5;
		add(toolBar, toolBarC);

		GridBagConstraints leftPanelC = new GridBagConstraints();
		leftPanelC.fill = GridBagConstraints.BOTH;
		leftPanelC.weightx = 0.2;
		leftPanelC.weighty = 1;
		leftPanelC.gridx = 0;
		leftPanelC.gridy = 1;
		leftPanelC.gridwidth = 1;
		add(leftPanel, leftPanelC);

		GridBagConstraints tableScrollPaneC = new GridBagConstraints();
		tableScrollPaneC.weightx = 0.8;
		tableScrollPaneC.weighty = 1;
		tableScrollPaneC.fill = GridBagConstraints.BOTH;
		tableScrollPaneC.gridx = 1;
		tableScrollPaneC.gridy = 1;
		tableScrollPaneC.gridwidth = 4;
		add(tableTabs, tableScrollPaneC);
	}

	protected void addButtons(JToolBar toolBar) {
		JButton button = null;

		// undo
		undoButton = makeNavigationButton("Back", UNDO, "Undo", "Undo");
		toolBar.add(undoButton);

		// redo
		redoButton = makeNavigationButton("Forward", REDO, "Redo", "Redo");
		toolBar.add(redoButton);

		toolBar.addSeparator(new Dimension(30, 0));

		// add
		button = makeNavigationButton("Plus", ADD, "Add", "Add");
		toolBar.add(button);

		// edit
		button = makeNavigationButton("Write", EDIT, "Edit", "Edit");
		toolBar.add(button);

		// remove
		button = makeNavigationButton("Minus", DELETE, "Remove", "Remove");
		toolBar.add(button);

		toolBar.addSeparator(new Dimension(30, 0));

		// save
		button = makeNavigationButton("Save", SAVE, "Save", "Save");
		toolBar.add(button);

		// print
		button = makeNavigationButton("Printer", PRINT, "Print", "Print");
		toolBar.add(button);

		// logout
		button = makeNavigationButton("Lock", LOGOUT, "Logout", "Logout");
		toolBar.add(button);

		// separator
		toolBar.addSeparator(new Dimension(30, 0));

		// search
		button = makeNavigationButton("Search", SEARCH, "Search", "Search");
		toolBar.add(button);

		searchField.setColumns(10);
		searchField.addActionListener(this);
		searchField.setActionCommand(TEXT_ENTERED);
		toolBar.add(searchField);
		undo = false;
		redo = false;
		undoRedoButtons();

	}

	protected JButton makeNavigationButton(String imageName,
			String actionCommand, String toolTipText, String altText) {
		// Look for the image.
		String imgLocation = "images/" + imageName + ".png";
		URL imageURL = GUISwing.class.getResource(imgLocation);

		// Create and initialize the button.
		JButton button = new JButton();
		button.setActionCommand(actionCommand);
		button.setToolTipText(toolTipText);
		button.addActionListener(this);

		if (imageURL != null) { // image found
			button.setIcon(new ImageIcon(imageURL, altText));
		} else { // no image found
			button.setText(altText);
			System.err.println("Resource not found: " + imgLocation);
		}

		return button;
	}

	public void actionPerformed(ActionEvent e) {
		String cmd = e.getActionCommand();

		// Handle each button.
		if (UNDO.equals(cmd) || REDO.equals(cmd)) {
			boolean undoRedo = false;
			UndoRedoItem urItem = new UndoRedoItem();
			
			if (UNDO.equals(cmd))
				undoRedo = true;
			else
				undoRedo = false;
			
			if (undoRedo)
				urItem = undoStack.pop();
			else
				urItem = redoStack.pop();
			
			if (urItem.getAction().endsWith("E")){
				tableTabs.setSelectedIndex(0);
			}
			else if (urItem.getAction().endsWith("I")){
				tableTabs.setSelectedIndex(1);
			}
			else
				tableTabs.setSelectedIndex(2);

			if (urItem.getAction().equals("AddE")) {
				int undoIndex = urItem.getRow();
				UndoRedoItem redoItem = new UndoRedoItem("RemoveE", undoIndex,
						(Item) expenseModel.getExpenseList().get(undoIndex));
				
				if (undoRedo) {
					redoStack.push(redoItem);
					redo = true;
				} else {
					undoStack.push(redoItem);
					undo = true;
				}

				myProfile.getWallet().deleteExpense(undoIndex);
				expenseTable.repaint();
				search();
			}

			else if (urItem.getAction().equals("EditE")) {
				int undoIndex = urItem.getRow();
				Expense undoExpense = (Expense) urItem.getUrItem();

				Expense oldEx = expenseModel.getExpenseList().get(undoIndex);
				Expense redoExpense = new Expense(oldEx.getDescription(),
						oldEx.getDate(), oldEx.getAmt(), oldEx.getCategory(),
						oldEx.getPaymentMethod(), oldEx.getIndex());

				UndoRedoItem redoItem = new UndoRedoItem("EditE", undoIndex,
						redoExpense);

				if (undoRedo) {
					redoStack.push(redoItem);
					redo = true;
				} else {
					undoStack.push(redoItem);
					undo = true;
				}

				myProfile.getWallet().editExpense(undoExpense.getDescription(),
						undoExpense.getDate(), undoExpense.getAmt(),
						undoExpense.getCategory(),
						undoExpense.getPaymentMethod(),
						expenseModel.getExpenseList().get(undoIndex));

				expenseTable.repaint();
				search();
			}

			else if (urItem.getAction().equals("RemoveE")) {
				int undoIndex = urItem.getRow();
				UndoRedoItem redoItem = new UndoRedoItem("AddE", undoIndex,
						urItem.getUrItem());

				if (undoRedo) {
					redoStack.push(redoItem);
					redo = true;
				} else {
					undoStack.push(redoItem);
					undo = true;
				}

				Expense undoExpense = (Expense) urItem.getUrItem();

				myProfile.getWallet().addExpense(undoExpense.getDescription(),
						undoExpense.getDate(), undoExpense.getAmt(),
						undoExpense.getCategory(),
						undoExpense.getPaymentMethod(), undoIndex);

				expenseTable.repaint();
				search();
			}
			
			else if (urItem.getAction().equals("AddI")) {
				int undoIndex = urItem.getRow();
				UndoRedoItem redoItem = new UndoRedoItem("RemoveI", undoIndex,
						(Item) incomeModel.getIncomeList().get(undoIndex));

				if (undoRedo) {
					redoStack.push(redoItem);
					redo = true;
				} else {
					undoStack.push(redoItem);
					undo = true;
				}

				myProfile.getWallet().deleteIncome(undoIndex);
				incomeTable.repaint();
				search();
			}

			else if (urItem.getAction().equals("EditI")) {
				int undoIndex = urItem.getRow();
				Income undoIncome = (Income) urItem.getUrItem();

				Income oldIn = incomeModel.getIncomeList().get(undoIndex);
				Income redoIncome = new Income(oldIn.getDescription(),
						oldIn.getDate(), oldIn.getAmt(), oldIn.getIndex());

				UndoRedoItem redoItem = new UndoRedoItem("EditI", undoIndex,
						redoIncome);

				if (undoRedo) {
					redoStack.push(redoItem);
					redo = true;
				} else {
					undoStack.push(redoItem);
					undo = true;
				}

				myProfile.getWallet().editIncome(undoIncome.getDescription(),
						undoIncome.getDate(), undoIncome.getAmt(),
						incomeModel.getIncomeList().get(undoIndex));

				incomeTable.repaint();
				search();
			}

			else if (urItem.getAction().equals("RemoveI")) {
				int undoIndex = urItem.getRow();
				UndoRedoItem redoItem = new UndoRedoItem("AddI", undoIndex,
						urItem.getUrItem());

				if (undoRedo) {
					redoStack.push(redoItem);
					redo = true;
				} else {
					undoStack.push(redoItem);
					undo = true;
				}

				Income undoIncome = (Income) urItem.getUrItem();

				myProfile.getWallet().addIncome(undoIncome.getDescription(),
						undoIncome.getDate(), undoIncome.getAmt(), undoIndex);

				incomeTable.repaint();
				search();
			}
			
			else if (urItem.getAction().equals("AddB")) {
				int undoIndex = urItem.getRow();
				UndoRedoItem redoItem = new UndoRedoItem("RemoveB", undoIndex,
						(Item) billModel.getBillList().get(undoIndex));

				if (undoRedo) {
					redoStack.push(redoItem);
					redo = true;
				} else {
					undoStack.push(redoItem);
					undo = true;
				}

				myProfile.getWallet().deleteBill(undoIndex);
				billTable.repaint();
				search();
			}

			else if (urItem.getAction().equals("EditB")) { //not functioning yet
				int undoIndex = urItem.getRow();
				Bill undoBill = (Bill) urItem.getUrItem();

				Bill oldBill = billModel.getBillList().get(undoIndex);
				Bill redoBill = new Bill(oldBill.getDescription(),
						oldBill.getLastPaidDate(), oldBill.getNextPayDate(), oldBill.getIndex());

				UndoRedoItem redoItem = new UndoRedoItem("EditB", undoIndex,
						redoBill);

				if (undoRedo) {
					redoStack.push(redoItem);
					redo = true;
				} else {
					undoStack.push(redoItem);
					undo = true;
				}

				myProfile.getWallet().editBill(undoBill.getDescription(),
						undoBill.getLastPaidDate(), undoBill.getNextPayDate(),
						billModel.getBillList().get(undoIndex));

				billTable.repaint();
				search();
			}
			
			else if (urItem.getAction().equals("PayB")) { //not functioning yet
			}

			else if (urItem.getAction().equals("RemoveB")) {
				int undoIndex = urItem.getRow();
				UndoRedoItem redoItem = new UndoRedoItem("AddB", undoIndex,
						urItem.getUrItem());

				if (undoRedo) {
					redoStack.push(redoItem);
					redo = true;
				} else {
					undoStack.push(redoItem);
					undo = true;
				}

				Bill undoBill = (Bill) urItem.getUrItem();

				myProfile.getWallet().addBill(undoBill.getDescription(),
						undoBill.getLastPaidDate(), undoBill.getNextPayDate(), undoIndex);

				billTable.repaint();
				search();
			}

			if (undoStack.isEmpty())
				undo = false;
			if (redoStack.isEmpty())
				redo = false;
			
			undoRedoButtons();
		}

		else if (ADD.equals(cmd)) {
			if (tableTabs.getSelectedIndex() == 0) {
				addExpense();
			} else if (tableTabs.getSelectedIndex() == 1) {
				addIncome();
			} else {
				addBill();
			}
			search();
		}

		else if (EDIT.equals(cmd)) {
			if (tableTabs.getSelectedIndex() == 0) {
				editExpense();
			} else if (tableTabs.getSelectedIndex() == 1) {
				editIncome();
			} else {
				editBill();
			}
			search();
		}

		else if (DELETE.equals(cmd)) {
			if (tableTabs.getSelectedIndex() == 0) {
				delExpense();
			} else if (tableTabs.getSelectedIndex() == 1) {
				delIncome();
			} else {
				delBill();
			}
			search();
		}

		else if (PRINT.equals(cmd)) {
			try {
				if (tableTabs.getSelectedIndex() == 0) {
					expenseTable.print();
				} else if (tableTabs.getSelectedIndex() == 1) {
					incomeTable.print();
				} else {
					billTable.print();
				}
			} catch (PrinterException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}
		
		else if (SAVE.equals(cmd)) {
			Helper.printAll(myProfile);
			myProfile.writeFile();
		}

		else if (LOGOUT.equals(cmd)) {
			this.setVisible(false);
			loginProcess();
			this.setVisible(true);
		}

		else if (SEARCH.equals(cmd)) { // text field
			search();
		}
	}

	/**
	 * Create the GUI and show it. For thread safety, this method should be
	 * invoked from the event dispatch thread.
	 */
	public static void createAndShowGUI() {
		// Create and set up the window.
		JFrame frame = new JFrame("EzXpns");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		// i create a GUISwing. this will be the only one in the prog
		GUISwing myGUI = new GUISwing();
		myGUI.loginProcess();

		// Add content to the window.
		frame.add(myGUI);

		// Display the window.
		frame.pack();
		frame.setVisible(true);
		frame.setLocationRelativeTo(null);
	}

	public void loginProcess() {
		while (true) {
			int loginStatus;
			String loginInfo[] = GUISwing.showLoginDialog(); // call login
																// dialog
			if (loginInfo == null) { // exit if login cancelled
				System.exit(0);
			}

			// perform login
			myProfile = new Profile(loginInfo[0]);
			loginStatus = myProfile.login(loginInfo[1]);
			if (loginStatus == 0) {
				// login succeed
				System.out.println("login succeed");
				break;
			}
			if (loginStatus == 1) {
				// account do not exist. create account.
				Object[] acctInfo = GUISwing.showCreateAcctDialog(loginInfo[0]);
				if (acctInfo == null) {
					System.exit(0);
				}
				myProfile = new Profile((String) acctInfo[0]);
				myProfile.createAcct((String) acctInfo[1],
						(BigDecimal) acctInfo[2], (Calendar) acctInfo[3],
						(BigDecimal) acctInfo[4]);
				myProfile.readFile();
				break;
			}
			if (loginStatus == 2) {
				continue;
			}
		}

		expenseModel.setWallet(myProfile.getWallet());
		incomeModel.setWallet(myProfile.getWallet());
		billModel.setWallet(myProfile.getWallet());
		alertsList.setModel(myProfile.getWallet().getAlert().getAlertList());

		budgetLabel.setText("$ "
				+ myProfile.getWallet().getBalance().toString());
		// Allows for the updating of the budget
		myProfile.getWallet().addPropertyChangeListener(
				new PropertyChangeListener() {
					public void propertyChange(PropertyChangeEvent evt) {
						// if the state change is the one we're interested in...
						if (evt.getPropertyName().equals("balance")) {
							budgetLabel.setText("$ "
									+ myProfile.getWallet().getBalance()
											.toString()); // show it in the GUI
							// if budget drops below 1000, color of budgetLabel
							// changes to pink
							if (((BigDecimal) evt.getNewValue())
									.compareTo(new BigDecimal(1000)) < 1)
								budgetLabel.setBackground(new Color(255, 153,
										153));
							if (((BigDecimal) evt.getNewValue())
									.compareTo(new BigDecimal(1000)) >= 1)
								budgetLabel.setBackground(new Color(204, 204,
										255));
						}
					}
				});

	}

	public static String[] showLoginDialog() {
		String[] loginInfo = null;

		JTextField userField = new JTextField();
		JPasswordField passField = new JPasswordField();

		final JComponent[] inputs = new JComponent[] { new JLabel("Username"),
				userField, new JLabel("Password"), passField };
		JOptionPane loginPane = new JOptionPane(inputs,
				JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
		JDialog dialog = loginPane.createDialog("Login");
		dialog.setContentPane(loginPane);
		dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
		dialog.pack();

		dialog.setVisible(true);

		int n = (int) loginPane.getValue();
		if (n == JOptionPane.OK_OPTION) {
			// weizhi your methods here start
			String userName = userField.getText();
			String password = new String(passField.getPassword());
			loginInfo = new String[] { userName, password };
		} else if (n == JOptionPane.CANCEL_OPTION) {

		}
		return loginInfo;
	}

	public static Object[] showCreateAcctDialog(String user) {
		Object[] acctInfo = null;

		JTextField userField = new JTextField(user);
		JPasswordField passField = new JPasswordField();
		JTextField salaryAmtField = new JTextField();
		JTextField balanceField = new JTextField();
		JCalendar payDayField = new JCalendar();

		final JComponent[] inputs = new JComponent[] { new JLabel("Username"),
				userField, new JLabel("Password"), passField,
				new JLabel("Salary Amount"), salaryAmtField,
				new JLabel("Balance"), balanceField, new JLabel("Pay day"),
				payDayField };
		JOptionPane createAcctPane = new JOptionPane(inputs,
				JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
		JDialog dialog = createAcctPane.createDialog("Create Account");
		dialog.setContentPane(createAcctPane);
		dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
		dialog.pack();

		dialog.setVisible(true);

		int n = (int) createAcctPane.getValue();
		if (n == JOptionPane.OK_OPTION) {
			// Retrieve info
			String userName = userField.getText();
			String password = new String(passField.getPassword());
			BigDecimal salaryAmt = new BigDecimal(salaryAmtField.getText());
			Calendar payDay = payDayField.getCalendar();
			BigDecimal balance = new BigDecimal(balanceField.getText());

			acctInfo = new Object[] { userName, password, salaryAmt, payDay,
					balance };
		} else if (n == JOptionPane.CANCEL_OPTION) {

		}
		return acctInfo;
	}

	/*
	 * public GUISwing() { super(new BorderLayout());
	 * 
	 * // Create the toolbar. JToolBar toolBar = new JToolBar();
	 * addButtons(toolBar); toolBar.setFloatable(false);
	 * toolBar.setRollover(true);
	 * 
	 * // Create the text area used for output. Request // enough space for 5
	 * rows and 30 columns. textArea = new JTextArea(50, 30);
	 * textArea.setEditable(false);
	 * 
	 * JPanel leftPanel = new JPanel(); leftPanel.setLayout(new
	 * BoxLayout(leftPanel, BoxLayout.Y_AXIS));
	 * leftPanel.setBorder(BorderFactory.createLineBorder(Color.black));
	 * leftPanel.setPreferredSize(new Dimension(150,100)); //set size of left
	 * panel
	 * 
	 * /* Commented out by Richard Yeo JCheckBox foodCheck = new
	 * JCheckBox("Food"); JCheckBox beverageCheck = new JCheckBox("Beverage");
	 * JCheckBox utilityCheck = new JCheckBox("Utility"); JCheckBox
	 * transportCheck = new JCheckBox("Transport"); JCheckBox etcCheck = new
	 * JCheckBox("ETC");
	 */

	/*
	 * Commented out by Jerrold Law chinButton.addItemListener(this);
	 * glassesButton.addItemListener(this); hairButton.addItemListener(this);
	 * teethButton.addItemListener(this);
	 */

	/*
	 * Commented out by Richard Yeo leftPanel.add(new JLabel(
	 * " Filters                                                                            "
	 * )); leftPanel.add(new JLabel(" "));
	 * 
	 * leftPanel.add(foodCheck); leftPanel.add(beverageCheck);
	 * leftPanel.add(utilityCheck); leftPanel.add(transportCheck);
	 * leftPanel.add(etcCheck);
	 * 
	 * leftPanel.add(new JLabel(" "));
	 * 
	 * leftPanel.add(new JLabel(" Budget:"));
	 */
	/*
	 * //Add in alerts label and then align them at the centre JLabel label =
	 * new JLabel("Alerts"); label.setAlignmentX(CENTER_ALIGNMENT);
	 * leftPanel.add(label);
	 * 
	 * TableColumnModel m = table.getColumnModel();
	 * m.getColumn(2).setCellRenderer(new RenderPrice());
	 * 
	 * table.setPreferredScrollableViewportSize(new Dimension(500, 70));
	 * table.setFillsViewportHeight(true); table.setAutoCreateRowSorter(true);
	 * 
	 * // Create the scroll pane and add the table to it. JPanel tableContainer
	 * = new JPanel();
	 * 
	 * JScrollPane tableScrollPane = new JScrollPane();
	 * tableScrollPane.setViewportView(table);
	 * tableContainer.add(tableScrollPane);
	 * 
	 * // Lay out the main panel. setPreferredSize(new Dimension(1350, 650));
	 * 
	 * add(toolBar, BorderLayout.PAGE_START); add(leftPanel, BorderLayout.WEST);
	 * add(tableScrollPane, BorderLayout.CENTER);
	 * 
	 * //i edited this segment start while(true){ int status =
	 * showLoginDialog(); if(status == 0){ System.out.printf("login succeed\n");
	 * expenseModel.setWallet(myProfile.getWallet()); break; } else if(status ==
	 * 1){ //call gui for create acct //myProfile.createAcct(stuff here);
	 * //myProfile.read();
	 * System.out.printf("acct dont exist. call create acct\n"); break; } else{
	 * //display wrong password msg System.out.printf("wrong password\n"); } }
	 * //edit end }
	 */

	public void search() {
		final String text = searchField.getText();

		// Simple search
		RowFilter<Object, Object> filter = new RowFilter<Object, Object>() {
			public boolean include(
					Entry<? extends Object, ? extends Object> entry) {
				for (int i = entry.getValueCount() - 1; i >= 0; i--) {
					if (entry.getStringValue(i).contains(text)) {
						return true;
					}
				}
				return false;
			}
		};

		RowFilter col_filter = RowFilter.regexFilter(text, 1);// Set filter to
																// search only
																// col
																// 1:descripton
																// field
		expenseSorter.setRowFilter(null);
		expenseSorter.setRowFilter(filter); // filter for simple search
		expenseSorter.setRowFilter(col_filter);
		expenseTable.setRowSorter(expenseSorter);

		col_filter = RowFilter.regexFilter(text, 0);
		incomeSorter.setRowFilter(null);
		incomeSorter.setRowFilter(filter); // filter for simple search
		incomeSorter.setRowFilter(col_filter);
		incomeTable.setRowSorter(incomeSorter);

		billSorter.setRowFilter(null);
		billSorter.setRowFilter(filter); // filter for simple search
		billSorter.setRowFilter(col_filter);
		billTable.setRowSorter(billSorter);
	}

	private void addPayBillButtons() {

		AbstractAction pay = new AbstractAction() {

			@Override
			public void actionPerformed(ActionEvent e) {
				payBill();
			}
		};

		TableColumn tc = billTable.getColumnModel().getColumn(3);

		JButton payBill = new JButton("Pay Bill");
		ButtonColumn bc = new ButtonColumn(billTable, pay, 3);
		tc.setCellRenderer(bc);
	}

	public void addExpense() {
		categoryBox = new JComboBox<String>(categoryBoxItems);
		paymentMethodBox = new JComboBox<String>(paymentMethodBoxItems);
		JTextField descriptionField = new JTextField();
		JTextField price = new JTextField();
		JCalendar date = new JCalendar();

		final JComponent[] inputs = new JComponent[] { new JLabel("Category"),
				categoryBox, new JLabel("Description"), descriptionField,
				new JLabel("Expense Amount"), price, new JLabel("Date"), date,
				new JLabel("Payment Method"), paymentMethodBox };
		int n = JOptionPane.showConfirmDialog(null, inputs, "Add Expense",
				JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
		if (n == JOptionPane.OK_OPTION) {
			int row = -1;
			try {
				row = expenseTable.convertRowIndexToModel(expenseTable
						.getSelectedRow());
			} catch (IndexOutOfBoundsException e2) {
				row = -1;
			}

			myProfile.getWallet().addExpense(descriptionField.getText(),
					date.getCalendar(), new BigDecimal(price.getText()),
					(String) categoryBox.getSelectedItem(),
					(String) paymentMethodBox.getSelectedItem(), row + 1);
			undoStack.push(new UndoRedoItem("AddE", row + 1, null));
			newAction();

			expenseTable.repaint();
		}
	}

	public void editExpense() {
		int row = -1;
		try {
			row = expenseTable.convertRowIndexToModel(expenseTable
					.getSelectedRow());
		} catch (IndexOutOfBoundsException e2) {
			row = -1;
		}

		Expense oldEx = expenseModel.getExpenseList().get(row);
		String oldCat = oldEx.getCategory();
		String oldDes = oldEx.getDescription();
		String oldAmt = oldEx.getAmt().toString();
		Calendar oldDat = oldEx.getDate();
		String oldPM = oldEx.getPaymentMethod();
		int oldIndex = oldEx.getIndex();

		categoryBox = new JComboBox<String>(categoryBoxItems);
		categoryBox.setSelectedItem(oldCat);

		paymentMethodBox = new JComboBox<String>(paymentMethodBoxItems);
		paymentMethodBox.setSelectedItem(oldPM);

		JTextField descriptionField = new JTextField(oldDes);

		JTextField price = new JTextField(oldAmt);

		JCalendar date = new JCalendar();
		date.setCalendar(oldDat);

		final JComponent[] inputs = new JComponent[] { new JLabel("Category"),
				categoryBox, new JLabel("Description"), descriptionField,
				new JLabel("Expense Amount"), price, new JLabel("Date"), date,
				new JLabel("Payment Method"), paymentMethodBox };
		int n = JOptionPane.showConfirmDialog(null, inputs, "Add Expense",
				JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
		if (n == JOptionPane.OK_OPTION) {

			String newCat = (String) categoryBox.getSelectedItem();
			String newDes = descriptionField.getText();
			BigDecimal newAmt = new BigDecimal(price.getText());
			Calendar newDat = date.getCalendar();
			String newPM = (String) paymentMethodBox.getSelectedItem();

			Expense undoExpense = new Expense(oldDes, oldDat, new BigDecimal(
					oldAmt), oldCat, oldPM, oldIndex);
			undoStack.push(new UndoRedoItem("EditE", row, undoExpense));
			newAction();

			myProfile.getWallet().editExpense(newDes, newDat, newAmt, newCat,
					newPM, oldEx);
		}
		expenseTable.repaint();
	}

	public void delExpense() {
		int row = -1;
		try {
			row = expenseTable.convertRowIndexToModel(expenseTable
					.getSelectedRow());
		} catch (IndexOutOfBoundsException e2) {
		}

		undoStack.push(new UndoRedoItem("RemoveE", row, myProfile.getWallet()
				.getExpenseList().get(row)));
		newAction();

		myProfile.getWallet().deleteExpense(row);

		expenseTable.repaint();
		search();

	}

	public void addIncome() {
		JTextField descriptionField = new JTextField();
		JTextField amount = new JTextField();
		JCalendar date = new JCalendar();

		final JComponent[] inputs = new JComponent[] {
				new JLabel("Description"), descriptionField,
				new JLabel("Amount"), amount, new JLabel("Date"), date };
		int n = JOptionPane.showConfirmDialog(null, inputs, "Add Expense",
				JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);

		if (n == JOptionPane.OK_OPTION) {
			int row = -1;
			try {
				row = incomeTable.convertRowIndexToModel(incomeTable
						.getSelectedRow());
			} catch (IndexOutOfBoundsException e2) {
				row = -1;
			}

			myProfile.getWallet().addIncome(descriptionField.getText(),
					date.getCalendar(), new BigDecimal(amount.getText()),
					row + 1);
			undoStack.push(new UndoRedoItem("AddI", row + 1, null));
			newAction();
		}
		incomeTable.repaint();
	}

	public void editIncome() {
		int row = -1;
		try {
			row = incomeTable.convertRowIndexToModel(incomeTable
					.getSelectedRow());
		} catch (IndexOutOfBoundsException e2) {
			row = -1;
		}
		
		Income oldIn = incomeModel.getIncomeList().get(row);
		String oldDes = (String) oldIn.getDescription();
		String oldAmt = oldIn.getAmt().toString();
		Calendar oldDat = oldIn.getDate();
		int oldIndex = oldIn.getIndex();

		JTextField descriptionField = new JTextField(oldDes);
		JTextField amt = new JTextField(oldAmt);
		JCalendar date = new JCalendar(oldDat);

		final JComponent[] inputs = new JComponent[] {
				new JLabel("Description"), descriptionField,
				new JLabel("Income Amount"), amt, new JLabel("Date"), date };
		int n = JOptionPane.showConfirmDialog(null, inputs, "Add Expense",
				JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
		if (n == JOptionPane.OK_OPTION) {
			try {
				String newDes = descriptionField.getText();
				BigDecimal newAmt = new BigDecimal(amt.getText());
				Calendar newDat = date.getCalendar();

				Income undoIncome = new Income(oldDes, oldDat, new BigDecimal(
						oldAmt), oldIndex);
				undoStack.push(new UndoRedoItem("EditI", row, undoIncome));
				newAction();

				myProfile.getWallet().editIncome(newDes, newDat, newAmt, oldIn);
			} catch (Exception e1) {
				e1.printStackTrace();
			}
		}
		incomeTable.repaint();
	}

	public void delIncome() {
		int row = -1;
		try {
			row = incomeTable.convertRowIndexToModel(incomeTable
					.getSelectedRow());
		} catch (IndexOutOfBoundsException e2) {
		}

		undoStack.push(new UndoRedoItem("RemoveI", row, myProfile.getWallet()
				.getIncomeList().get(row)));
		newAction();

		myProfile.getWallet().deleteIncome(row);
		incomeTable.repaint();
		search();

	}

	public void addBill() {
		JTextField descriptionField = new JTextField();
		JCalendar lastPaidDate = new JCalendar();
		JCalendar nextPayDate = new JCalendar();

		final JComponent[] inputs = new JComponent[] {
				new JLabel("Description"), descriptionField,
				new JLabel("Last Paid Date"), lastPaidDate,
				new JLabel("Next Pay Date"), nextPayDate };
		int n = JOptionPane.showConfirmDialog(null, inputs, "Add Expense",
				JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);

		if (n == JOptionPane.OK_OPTION) {
			int row = -1;
			try {
				row = incomeTable.convertRowIndexToModel(incomeTable
						.getSelectedRow());
			} catch (IndexOutOfBoundsException e2) {
				row = -1;
			}

			myProfile.getWallet().addBill(descriptionField.getText(),
					lastPaidDate.getCalendar(), nextPayDate.getCalendar(), row + 1);
			undoStack.push(new UndoRedoItem("AddB", row + 1, null));
			newAction();
		}
		billTable.repaint();
	}

	public void editBill() {
		int row = -1;
		try {
			row = billTable.convertRowIndexToModel(billTable.getSelectedRow());
		} catch (IndexOutOfBoundsException e2) {
			row = -1;
		}

		String oldDes = (String) billModel.getValueAt(row, 0);
		Date oldPDat = (Date) billModel.getValueAt(row, 1);
		Date oldNDat = (Date) billModel.getValueAt(row, 2);

		JTextField descriptionField = new JTextField(oldDes);
		JCalendar pDate = new JCalendar(oldPDat);
		JCalendar nDate = new JCalendar(oldNDat);

		final JComponent[] inputs = new JComponent[] {
				new JLabel("Bill Description"), descriptionField,
				new JLabel("Last Payment Date"), pDate,
				new JLabel("Next Payment Date"), nDate };
		int n = JOptionPane.showConfirmDialog(null, inputs, "Add Bill",
				JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);

		if (n == JOptionPane.OK_OPTION) {
			try {
				billTable.setValueAt(descriptionField.getText(), row, 0);
				billTable.setValueAt(pDate.getCalendar(), row, 1);
				billTable.setValueAt(nDate.getCalendar(), row, 2);
				myProfile.getWallet().getAlert();
			} catch (Exception e1) {
				e1.printStackTrace();
			}
		}
		billTable.repaint();
	}

	public void payBill() {

		int bRow = -1;
		try {
			bRow = billTable.convertRowIndexToModel(billTable.getSelectedRow());

		} catch (IndexOutOfBoundsException e2) {
			bRow = -1;
		}

		categoryBox = new JComboBox<String>(categoryBoxItems);
		paymentMethodBox = new JComboBox<String>(paymentMethodBoxItems);
		JTextField descriptionField = new JTextField();
		JTextField price = new JTextField();
		JCalendar date = new JCalendar();

		final JComponent[] inputs = new JComponent[] { new JLabel("Category"),
				categoryBox, new JLabel("Description"), descriptionField,
				new JLabel("Bill Amount"), price, new JLabel("Date"), date,
				new JLabel("Payment Method"), paymentMethodBox };

		categoryBox.setSelectedItem("Utility");
		descriptionField.setText((String) billModel.getValueAt(bRow, 0));

		int n = JOptionPane.showConfirmDialog(null, inputs, "Pay Bill",
				JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
		if (n == JOptionPane.OK_OPTION) {

			int eRow = -1;
			try {
				eRow = expenseTable.convertRowIndexToModel(expenseTable
						.getSelectedRow());
			} catch (IndexOutOfBoundsException e2) {
				eRow = -1;
			}

			myProfile.getWallet().addExpense(descriptionField.getText(),
					date.getCalendar(), new BigDecimal(price.getText()),
					(String) categoryBox.getSelectedItem(),
					(String) paymentMethodBox.getSelectedItem(), eRow + 1);

			myProfile.getWallet().payBill(billModel.getBillAt(bRow),
					date.getCalendar());

			billTable.repaint();
			expenseTable.repaint();
		}
	}

	public void delBill() {
		int row = -1;
		try {
			row = billTable.convertRowIndexToModel(billTable.getSelectedRow());
		} catch (IndexOutOfBoundsException e2) {
		}
		
		undoStack.push(new UndoRedoItem("RemoveB", row, myProfile.getWallet()
				.getBillList().get(row)));
		newAction();
		
		myProfile.getWallet().deleteBill(row);
		billTable.repaint();
		search();

	}

	public void undoRedoButtons() {
		if (undo) {
			String imgLocation = "images/Back.png";
			URL imageURL = GUISwing.class.getResource(imgLocation);
			undoButton.setIcon(new ImageIcon(imageURL, "Undo"));
			undoButton.setEnabled(true);
		} else {
			String imgLocation = "images/Back_disabled.png";
			URL imageURL = GUISwing.class.getResource(imgLocation);
			undoButton.setIcon(new ImageIcon(imageURL, "Undo"));
			undoButton.setEnabled(false);
		}

		if (redo) {
			String imgLocation = "images/Forward.png";
			URL imageURL = GUISwing.class.getResource(imgLocation);
			redoButton.setIcon(new ImageIcon(imageURL, "Redo"));
			redoButton.setEnabled(true);
		} else {
			String imgLocation = "images/Forward_disabled.png";
			URL imageURL = GUISwing.class.getResource(imgLocation);
			redoButton.setIcon(new ImageIcon(imageURL, "Redo"));
			redoButton.setEnabled(false);
		}
	}

	public void newAction() {
		redoStack.clear();
		undo = true;
		redo = false;
		undoRedoButtons();
	}

	/*
	 * public GUISwing() { super(new BorderLayout());
	 * 
	 * // Create the toolbar. JToolBar toolBar = new JToolBar();
	 * addButtons(toolBar); toolBar.setFloatable(false);
	 * toolBar.setRollover(true);
	 * 
	 * // Create the text area used for output. Request // enough space for 5
	 * rows and 30 columns. textArea = new JTextArea(50, 30);
	 * textArea.setEditable(false);
	 * 
	 * JPanel leftPanel = new JPanel(); leftPanel.setLayout(new
	 * BoxLayout(leftPanel, BoxLayout.Y_AXIS));
	 * leftPanel.setBorder(BorderFactory.createLineBorder(Color.black));
	 * leftPanel.setPreferredSize(new Dimension(150,100)); //set size of left
	 * panel
	 * 
	 * /* Commented out by Richard Yeo JCheckBox foodCheck = new
	 * JCheckBox("Food"); JCheckBox beverageCheck = new JCheckBox("Beverage");
	 * JCheckBox utilityCheck = new JCheckBox("Utility"); JCheckBox
	 * transportCheck = new JCheckBox("Transport"); JCheckBox etcCheck = new
	 * JCheckBox("ETC");
	 */

	/*
	 * Commented out by Jerrold Law chinButton.addItemListener(this);
	 * glassesButton.addItemListener(this); hairButton.addItemListener(this);
	 * teethButton.addItemListener(this);
	 */

	/*
	 * Commented out by Richard Yeo leftPanel.add(new JLabel(
	 * " Filters                                                                            "
	 * )); leftPanel.add(new JLabel(" "));
	 * 
	 * leftPanel.add(foodCheck); leftPanel.add(beverageCheck);
	 * leftPanel.add(utilityCheck); leftPanel.add(transportCheck);
	 * leftPanel.add(etcCheck);
	 * 
	 * leftPanel.add(new JLabel(" "));
	 * 
	 * leftPanel.add(new JLabel(" Budget:"));
	 */
	/*
	 * //Add in alerts label and then align them at the centre JLabel label =
	 * new JLabel("Alerts"); label.setAlignmentX(CENTER_ALIGNMENT);
	 * leftPanel.add(label);
	 * 
	 * TableColumnModel m = table.getColumnModel();
	 * m.getColumn(2).setCellRenderer(new RenderPrice());
	 * 
	 * table.setPreferredScrollableViewportSize(new Dimension(500, 70));
	 * table.setFillsViewportHeight(true); table.setAutoCreateRowSorter(true);
	 * 
	 * // Create the scroll pane and add the table to it. JPanel tableContainer
	 * = new JPanel();
	 * 
	 * JScrollPane tableScrollPane = new JScrollPane();
	 * tableScrollPane.setViewportView(table);
	 * tableContainer.add(tableScrollPane);
	 * 
	 * // Lay out the main panel. setPreferredSize(new Dimension(1350, 650));
	 * 
	 * add(toolBar, BorderLayout.PAGE_START); add(leftPanel, BorderLayout.WEST);
	 * add(tableScrollPane, BorderLayout.CENTER);
	 * 
	 * //i edited this segment start while(true){ int status =
	 * showLoginDialog(); if(status == 0){ System.out.printf("login succeed\n");
	 * expenseModel.setWallet(myProfile.getWallet()); break; } else if(status ==
	 * 1){ //call gui for create acct //myProfile.createAcct(stuff here);
	 * //myProfile.read();
	 * System.out.printf("acct dont exist. call create acct\n"); break; } else{
	 * //display wrong password msg System.out.printf("wrong password\n"); } }
	 * //edit end }
	 */

}